package hash;


// 自己实现一个哈希表玩
public class HashMap {

    static class Node{
        public int key;
        public int value;
        public Node next;

        public Node(int key, int value) {
            this.key = key;
            this.value = value;
        }
    }


    //  C R U D
    private Node[] quick_find;
    private int capacity; // 容量
    private static final double balance = 0.75; // 负载因子
    private int size; // 哈希表中存在多少元素 （键值对）




    public HashMap(){
        capacity = 101;
        quick_find = new Node[capacity];
        size = 0;
    }


    // 得需要一个动态扩容的方法
    // 自动 检测 负载系数 是否大于 负载因子 如果大于 自动扩容
    public void expand(){
        // 自动扩容
        if(size/capacity < balance){// 哈希冲突不严重
            return ;
        }
        Node[] increase = new Node[capacity*2];
        capacity = 2*capacity;

        for(int i = 0; i < capacity/2; i++){
            Node head = quick_find[i];
            if(head != null){
                int index = head.key%capacity;//新的下标
                increase[index] = head;
            }
        }
        quick_find = increase;
        return ;
    }




    // 作用 将 键值对 插入哈希表中 ，如果 当前 插入的 key 存在 则修改他的value 值即可 （不会出现插入失败的情况 ）
    public void put(int key,int value){
        //这里根据 key 的到一个哈希值 做数组下标
        // 避免哈希冲突 (采用取素数长度)
        expand();
        int index = key%capacity;
        Node head = quick_find[index];
        while(head != null){
            // 找这个key 是否存在了 如果存在 就 改变 value 否则 就以头插的方式 插入新的节点
            if( head.key == key ){
                head.value = value;
                return ;
            }
            head = head.next;
        }// 正常出这个循环 head == null,并且没找到 对应的 key
        // 这个元素是新的元素
        Node node = new Node(key,value);
        // 将元素 头插放入数组
        head = quick_find[index];
        node.next = head;
        quick_find[index] =  node;
        size++;
    }

    // get  哈希表中有 key 对应的value 返回value对象 否则 返回 null
    public Integer get(int key){
        int index = key%capacity;

        Node head = quick_find[index];
        while(head != null){
            if(head.key == key) return head.value;
            head = head.next;
        }
        return null;
    }

    // 删除 哈希表的键值对
    public void remove(int key){
        int index = key%capacity;

        Node head = quick_find[index];
        // 删除值的合法校验
        if(head == null || get(key) == null) return ;
        // 在链表中 找到待删除元素 将其删除 并返回新的头节点
        head = delete(head,key);
        quick_find[index] = head;
        size--;
    }
    // 从链表中删除 key 为 key 的元素 并返回新的头节点
    private Node delete(Node head, int key) {
        Node cur = head;
        Node prev = null;

        while(cur != null){
            if(cur.key == key){
                if(prev == null){
                    // 要删除的元素就是头节点
                    return head.next;
                }else {
                    prev.next = cur.next;
                }
                prev = cur;
                cur = cur.next;
            }
        }
        return head;
    }

    public static void main(String[] args) {
        HashMap map = new HashMap();
        map.put(1,2);
        map.put(1,3);
        map.put(1,4);
        map.put(102,3);
        map.put(2,5);
        map.put(3,9);
        map.remove(2);
    }

}
